home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK2.toast / Development Kits (Disc 2) / ScriptX / Draggable ScriptX Folders / utils / widgets / listbox.sx < prev    next >
Encoding:
Text File  |  1995-12-06  |  13.3 KB  |  550 lines  |  [TEXT/ttxt]

  1. class ListSelection (TwoDShape)
  2. class variables
  3.     fill:(new Brush color:BlackColor)
  4. instance vars
  5.     _descent
  6. class methods
  7.     method afterInit self #rest args -> (
  8.         apply nextMethod self args
  9.         ListSelection.fill.inkMode := @srcXor
  10.     )
  11. end
  12.  
  13. ------------------------
  14.  
  15. method init self { class ListSelection } #rest args #key \
  16.     width:(10) ->
  17.     local height := 10
  18.     local bounds := new Rect x2:width y2:height
  19.     apply NextMethod self boundary:bounds fill:ListSelection.fill args
  20. )
  21.  
  22. method afterInit self {class ListSelection } #rest args #key \
  23.     font:(theSystemFont) \
  24.     parent:         ->
  25. (
  26.     apply NextMethod self args
  27.     changeFont self font 1
  28.     if (not (isAKindOf parent TwoDPresenter)) do
  29.         report BadParameter "parent must be a TwoDPresenter!"
  30.     ThreadCriticalUp()
  31.     local subs := parent.subPresenters
  32.     if (subs = undefined) then
  33.         parent.subPresenters := #(self)
  34.     else
  35.         prepend subs self
  36.     self.presentedBy := parent
  37.     ThreadCriticalDown()
  38. )
  39.  
  40. method changeFont self {class ListSelection} font theLine ->
  41. (
  42.     self.height := font.leading
  43.     self._descent := font.descent - 2 -- frame offset
  44.     selectLine self theLine @dontAction
  45. )
  46.  
  47. method selectLine self {class ListSelection} the_line doAction ->
  48. (
  49.     self.y := self.height * (the_line - 1) + self._descent
  50. )
  51.  
  52. -----------------
  53.  
  54. class ListBox (TextPresenter)
  55. instance vars
  56.     numLines:0                -- number of lines in the list of text
  57.     _font
  58. end
  59.  
  60. method init self { class ListBox }  #rest args #key \
  61.     font:(theSystemFont)    \
  62.     width:(300)                \
  63.     list:(#())                ->
  64.     apply nextMethod self target:"" boundary:(new Rect x2:width y2:0) args 
  65.     SetDefaultAttr self @alignment @tty
  66.     self.font := font
  67.     self.inset.x := 5
  68.     self.list := list
  69. )
  70.  
  71. method fontGetter self {class ListBox} -> self._font
  72. method fontSetter self {class ListBox} newFont ->
  73. (
  74.     self._font := newFont
  75.     setDefaultAttr self @font newFont.font
  76.     setDefaultAttr self @leading newFont.leading
  77.     setDefaultAttr self @firstLineLeading (newFont.leading - newFont.descent + 2)
  78.     setDefaultAttr self @size newFont.fontSize
  79.     recalcHeight self
  80.     newFont
  81. )
  82.  
  83. method listSetter self {class ListBox} new_list -> 
  84. (
  85.     -- clear out targets
  86.     self.target := "" as String
  87.     
  88.     -- re-build lists
  89.     forEach new_list (item arg -> \
  90.             addMany self.target ((item as String) + "\r")) self
  91.             
  92.     -- select the first line of each column
  93.     self.numLines := new_list.size
  94.     recalcHeight self
  95.     new_list
  96. )
  97.  
  98. method listGetter self {class ListBox} ->
  99. (
  100.     local listText := self.target
  101.     local maxSize := size listText
  102.     local args := #(listText,1,0,maxSize)
  103.     local returnList := #()
  104.     repeat while (FindNthContext args @paragraph) do (
  105.         append returnList (CopyFromTo(listText,args[3],args[4] - 1))
  106.         args[3] := args[4]
  107.         args[4] := maxSize
  108.     )
  109.     returnList
  110. )
  111.  
  112. method getListOrdinal self {class ListBox} item ->
  113. (
  114.     local listText := self.target
  115.     local maxSize := size listText
  116.     local args := #(listText,1,0,maxSize)
  117.     local ord := 1
  118.     repeat while (FindNthContext args @paragraph) do (
  119.         if (item = (CopyFromTo(listText,args[3],args[4] - 1))) do
  120.             return ord
  121.         ord := ord + 1
  122.         args[3] := args[4]
  123.         args[4] := maxSize
  124.     )
  125.     return 0
  126. )
  127.  
  128.  
  129. method recalcHeight self {class ListBox} ->
  130. (
  131.     self.height := self.numLines*self.font.leading + self.font.descent
  132. )
  133.  
  134. global upReceiver
  135. global downReceiver
  136.  
  137. class ScrollBox(ScrollingPresenter)
  138. class variables
  139.     mouse:(new MouseDevice)
  140. instance variables
  141.     doubleClickTime:(getDblClickTime())
  142.     doubleClickAction:(undefined)
  143.     lastTime:0
  144.     lastLine:0
  145.     authordata:(undefined)
  146.     
  147.     downInterest
  148.     upInterest
  149.  
  150.     _selectedLine:0
  151.     selectAction:(undefined)
  152.     selection
  153.  
  154.     maxScroll:0
  155.     stepAmount:0
  156.     pageAmount:0
  157.     scrollDirection
  158.     frame:(new Frame)
  159.     tempPoint:(new Point)
  160.     _list
  161. end
  162.  
  163. method init self {class ScrollBox} #rest args #key \
  164.     font:(theSystemFont) ->
  165. (
  166.     self.stepAmount := font.leading
  167.     apply NextMethod self args
  168.     local targetP := self.targetPresenter
  169.     self.selection := new ListSelection font:font\
  170.         width:self.width parent:targetP
  171.  
  172.     local downInterest := new MouseDownEvent
  173.     self.downInterest := downInterest
  174.     downInterest.eventReceiver := downReceiver
  175.     local upInterest := new MouseUpEvent
  176.     self.upInterest := upInterest
  177.     upInterest.eventReceiver := upReceiver
  178.     downInterest.buttons := upInterest.buttons := @mouseButton1
  179.     downInterest.authordata := upInterest.authordata := self
  180.     downInterest.presenter := upInterest.presenter := self
  181.     downInterest.priority := upInterest.priority := 6
  182.     upInterest.matchedInterest := downInterest
  183. )
  184.  
  185. method afterInit self {class ScrollBox} #rest args #key \
  186.     hasScrollBar:(false) \
  187.     value: ->
  188. (
  189.     apply NextMethod self args
  190.  
  191.     local cp := self.clippingPresenter
  192.     InsetRect cp.boundary 2 2 @mutate
  193.     cp.stationary := true
  194.     cp.fill := WhiteBrush
  195.     self.stationary := true
  196.     if (hasScrollBar) do (
  197.         local vScroll := new SimpleScrollBar orientation:@vertical
  198.         vScroll.directDrag := true
  199.         vScroll.stepAmount := self.stepAmount
  200.         self.vertScrollBar := vScroll
  201.     )
  202.     self.horizScrollBarDisplayed := @none
  203.     if (value != unsupplied) do
  204.         self.value := value
  205.         
  206. )
  207.  
  208. method set presentedBy self {class ScrollBox} val ->
  209. (
  210.     nextMethod self val
  211.     if (val == undefined) then (
  212.         removeEventInterest self.upInterest
  213.         removeEventInterest self.downInterest
  214.         )
  215.     else (
  216.         addEventInterest self.downInterest
  217.         addEventInterest self.upInterest
  218.         )
  219.     val
  220. )
  221.  
  222. method recalcRegion self {class ScrollBox} ->
  223. (
  224.     NextMethod self
  225.     SetBoundary self.frame self.boundary
  226. )
  227.  
  228. method downReceiver self {class ScrollBox} theInterest theEvent ->
  229. (
  230.     local new_selected_line
  231.     self.needsTickle := true
  232.     local tempPoint := self.tempPoint
  233.     setTo tempPoint theEvent.surfaceCoords
  234.     SurfaceToLocal self.targetPresenter tempPoint @mutate
  235.     new_selected_line := ((tempPoint.y / self.stepAmount)  as ImmediateInteger) + 1
  236.     selectLine self new_selected_line @dontAction
  237.     @accept
  238. )
  239.  
  240. method upReceiver self {class ScrollBox} theInterest theEvent ->
  241. (
  242.     local selectedLine := self._selectedLine
  243.     self.needsTickle := false
  244.     
  245.     if (selectedLine = self.lastLine) then (
  246.         local doubleClickAction := self.doubleClickAction
  247.         if (((theEvent.timeStamp - self.lastTime) < self.doubleClickTime) and
  248.             doubleClickAction != undefined) then (
  249.             doubleClickAction self.authorData selectedLine
  250.             self.lastTime := 0
  251.         )
  252.         else
  253.             self.lastTime := theEvent.timeStamp
  254.     )
  255.     else (
  256.         self._selectedLine := -1 -- force @doAction to occur
  257.         selectLine self selectedLine @doAction
  258.         self.lastTime := theEvent.timeStamp
  259.     )
  260.     
  261.     self.lastLine := selectedLine
  262.     @accept
  263. )
  264.  
  265. method tickle self {class ScrollBox} clock ->
  266. (
  267.     local tempPoint := self.tempPoint
  268.     local screenCoords := ScrollBox.mouse.currentCoords
  269.     SetTo tempPoint screenCoords
  270.     ScreenToDisplay self.window.displaySurface tempPoint @mutate
  271.     SurfaceToLocal self tempPoint @mutate
  272.     local targetP := self.targetPresenter
  273.     
  274.     
  275.     local bbox := self.clippingPresenter.boundary
  276.     local y1 := bbox.y1
  277.     local y2 := bbox.y2
  278.     local mouseY := tempPoint.y
  279.         
  280.     if (mouseY < y1) then (
  281.         if (self._selectedLine > 0) do
  282.             repeatScrollAction self targetP @up
  283.     )
  284.     else if (mouseY > y2) then
  285.     (
  286.         if (self._selectedLine < self.numLines) do
  287.             repeatScrollAction self targetP @down
  288.     )
  289.     else (
  290.         LocalToSurface self tempPoint @mutate
  291.         SurfaceToLocal targetP tempPoint @mutate
  292.         self.selectedLine := \
  293.             ((tempPoint.y / self.stepAmount) as ImmediateInteger) + 1
  294.     )
  295. )
  296.  
  297. method repeatScrollAction self {class ScrollBox} targetPresenter direction ->
  298. (
  299.     local y  := -targetpresenter.y
  300.     local stepAmount := self.stepAmount
  301.     if (direction = @up) then (
  302.         local topPoint := y - stepAmount
  303.         scrollTo self 0 topPoint
  304.         if (topPoint < 0) do topPoint := 0
  305.         self.selectedLine := ((topPoint / stepAmount)  as ImmediateInteger) + 1
  306.     )
  307.     else if (direction = @down) do (
  308.         local bottomPoint := y + stepAmount
  309.         scrollTo self 0 bottomPoint
  310.         bottomPoint := bottomPoint + self.height
  311.         local newLine := ((bottomPoint / stepAmount)  as ImmediateInteger)
  312.         local numLines := self.numLines
  313.         if (newLine > numLines) do
  314.             newLine := numLines
  315.         self.selectedLine := newLine
  316.     )
  317. )
  318.  
  319. method draw self {class ScrollBox} surface clip ->
  320. (
  321.     NextMethod self surface clip
  322.     drawLoweredFrame self.frame surface clip self.globalTransform
  323. )
  324.  
  325. method layout self {class ScrollBox} ->
  326. (
  327.     ThreadCriticalUp() -- prevent visual jumping of vScroll
  328.         NextMethod self
  329.         local ht := self.height
  330.         self.maxScroll := self.targetPresenter.height - ht
  331.         local cp := self.clippingPresenter
  332.         cp.width := cp.width - 4
  333.         cp.height := cp.height - 4
  334.         
  335.         local stepAmount := self.stepAmount
  336.         -- page a line less than a scrollbox worth
  337.         self.pageAmount := (self.height/stepAmount - 1)*stepAmount
  338.         local vScroll := self.vertScrollBar
  339.         if (vScroll <> undefined) do (
  340.             vScroll.pageAmount := self.pageAmount
  341.             vScroll.y := 2
  342.             vScroll.height := ht - 4
  343.             vScroll.x := vScroll.x - 2
  344.             vScroll.stepAmount := stepAmount
  345.         )
  346.     ThreadCriticalDown()
  347.     self
  348. )
  349.  
  350. method selectLine self {class ScrollBox} theLine doAction ->
  351. (
  352.     if (theLine <> self._selectedLine and theLine > 0 and \
  353.         theLine <= self.numLines ) then (
  354.         ThreadCriticalUp()
  355.         if (doAction = @doAction and self.selectAction != undefined) do 
  356.             self.selectAction self.authorData theLine
  357.         selectLine self.selection theLine doAction
  358.         self._selectedLine := theLine
  359.         local lineHt := self.stepAmount
  360.         local startLine := round(-self.targetPresenter.y/lineHt) + 1
  361.         local endLine := \
  362.             (startLine + (self.height - 5 + lineHt)/lineHt - 1) as ImmediateInteger
  363.         if (theLine < startLine or theLine > endLine) do (
  364.             ScrollTo self 0 ((theLine - 1)*lineHt)
  365.         )
  366.         ThreadCriticalDown()
  367.     )
  368. )
  369.  
  370. method afterLoading self {class ScrollBox} stream ->
  371. (
  372.     NextMethod self self stream
  373.     load self.downInterest
  374.     load self.upInterest
  375. )
  376.  
  377. method fontSetter self {class ScrollBox} newFont ->
  378. (
  379.     self.stepAmount := newFont.leading
  380.     if (self.vertScrollBar != undefined) do
  381.         self.vertScrollBar.stepAmount := self.stepAmount
  382.     changeFont self.selection newFont self._selectedLine
  383.     layout self
  384.     newFont
  385. )
  386.  
  387.  
  388. method selectedLineGetter self {class ScrollBox} ->
  389.     self._selectedLine
  390.  
  391. method selectedLineSetter self {class ScrollBox} newLine -> 
  392. (
  393.     selectLine self newLine @doAction
  394.     newLine
  395. )
  396.  
  397. method numLinesGetter self {class ScrollBox} ->
  398. (
  399.     local stepAmount := self.stepAmount
  400.     ((self.targetPresenter.height)/stepAmount) as ImmediateInteger
  401. )
  402.  
  403. method widthSetter self {class ScrollBox} newWidth->
  404. (
  405.     self.selection.width := newWidth
  406.     self.targetPresenter.width := newWidth
  407.     NextMethod self newWidth
  408. )
  409.  
  410. method valueGetter self {class ScrollBox} ->
  411. (
  412.     GetNthKey self._list self._selectedLine
  413. )
  414.  
  415. method valueSetter self {class ScrollBox} newValue ->
  416. (
  417.     local scrollList := self._list
  418.     selectLine self (GetOrdOne scrollList (GetOne scrollList newValue)) @doAction
  419.     self.value
  420. )
  421.     
  422. method listGetter self {class ScrollBox} -> self._list
  423.  
  424. method fillGetter self {class ScrollBox} -> self.clippingPresenter.fill
  425. method fillSetter self {class ScrollBox} newFill ->
  426. (
  427.     self.clippingPresenter.fill := newFill
  428.     NextMethod self undefined
  429. )
  430.  
  431. class ScrollListBox(ScrollBox)
  432. end
  433.  
  434. method init self {class ScrollListBox} #rest args #key \
  435.     boundary:                        \
  436.     list:(#())                        \
  437.     font:(theSystemFont)            \
  438.     ->
  439. (
  440.     local targetPresenter := apply new ListBox \
  441.         width:boundary.width args
  442.     apply NextMethod self boundary:boundary \
  443.         targetPresenter:targetPresenter args
  444.     self.list := list
  445. )
  446.  
  447. method fontGetter self {class ScrollListBox} -> self.targetPresenter.font
  448. method fontSetter self {class ScrollListBox} newFont ->
  449. (
  450.     self.targetPresenter.font := newFont
  451.     NextMethod self newFont
  452. )
  453.  
  454. method listSetter self {class ScrollListBox} newList ->
  455. (
  456.     self._list := self.targetPresenter.list := newList
  457.     selectLine self 1 @dontAction    
  458.     layout self
  459.     newList
  460. )    
  461.  
  462. method numLinesGetter self {class ScrollListBox} -> self.targetPresenter.numLines
  463.  
  464. class MultiListBox(ScrollBox)
  465. instance variables
  466.     numColumns
  467. end
  468.  
  469. --sample list: #(#(1,@a),#(2,@b))
  470. --1 & 2 are in first column, a & b in second.  1&a are across
  471. --from one another as or 2&b
  472. method init self {class MultiListBox} #rest args #key \
  473.     boundary:                        \
  474.     font:(theSystemFont)            \
  475.     list:(#())                        \
  476.     numColumns:                        ->
  477. (
  478.     local targetPresenter := new TwoDMultiPresenter boundary:(copy boundary)
  479.     apply NextMethod self targetPresenter:targetPresenter \
  480.         boundary:boundary args
  481.     if (numColumns = unsupplied) do
  482.         numColumns := size list[1]
  483.     self.numColumns := numColumns
  484.     local columnWidth := self.clippingPresenter.width / numColumns
  485.     for i := 1 to numColumns do (
  486.         local lb := new ListBox width:columnWidth font:font
  487.         lb.x := (columnWidth * (i - 1))
  488.         append targetPresenter lb
  489.     )
  490.     self.list := list
  491. )
  492.  
  493. fn setFont aListBox font ->
  494. (
  495.     if (isAKindOf aListBox ListBox) do
  496.         aListBox.font := font
  497. )
  498.  
  499. method fontGetter self {class MultiListBox} ->
  500. (
  501.     local aListBox := chooseOne self.targetPresenter \
  502.         (a -> isAKindOf a ListBox) undefined
  503.     aListBox.font
  504. )
  505.  
  506. method fontSetter self {class MultiListBox} newFont ->
  507. (
  508.     foreach self.targetPresenter setFont newFont
  509.     NextMethod self newFont
  510. )
  511.  
  512. method listSetter self {class MultiListBox} newList ->
  513. (
  514.     self._list := newList
  515.     selectLine self 1 @dontAction
  516.     local targetP := self.targetPresenter
  517.     for i := 1 to self.numColumns do
  518.         targetP[i+1].list := for j in newList collect j[i]
  519.     targetP.height := targetP[2].height
  520.     layout self
  521.     newList
  522. )
  523.  
  524. method widthSetter self {class MultiListBox} val ->
  525. (
  526.     local origWidth, ratio, targetP, pos
  527.     
  528.     origWidth := self.width
  529.     ratio := val / origWidth
  530.     nextMethod self val
  531.     
  532.     targetP := self.targetPresenter
  533.     pos := 0
  534.     for pres in targetP do (
  535.         if (isAKindOf pres ListBox) do (
  536.             pres.x := pos
  537.             pres.width := ratio * pres.width
  538.             pos := pos + pres.width
  539.             )
  540.         )
  541.     val
  542. )
  543.  
  544. method numLinesGetter self {class MultiListBox} ->
  545. (
  546.     self.targetPresenter[2].numLines
  547. )
  548.